package sxe.core.cs511.team2_2;
import java.util.ListIterator;
import java.util.Vector;
/**
 * OVERVIEW: A collection of tracks.  Also counts people in a room by direction.
 * 				the direction into the room must be specified in camera coordinates.
 * 
 * The abstraction function is AF(c) = {a collection of active tracks in the system }
 * 
 * 
 * The rep invariant is none of the tracks in the collection can be null or duplicated.
 *  
 *   
 * @author skelly
 *
 */
public class Tracker {
	private double match_cutoff;
	private double inx,iny;
	private long last_add_time=0;
	private long last_add_time2=0;
	private int count=0;
	/**
	 * EFFECTS: initializes to empty collection with inward direction vector [in_x, in_y] (does not need to be of unit length) and match cutoff of 0.3 for distance between blob descriptors (0.5 is recommended)
	 * 			[-1,-1] specifies an inward direction of up and to the left in the camera's field of view.
	 */
	public Tracker(double in_x, double in_y){
		inx=in_x;
		iny=in_y;
		match_cutoff=0.9;
	}
	/**
	 * EFFECTS: initializes to empty collection with inward direction vector [in_x, in_y] (does not need to be of unit length) and match cutoff as specified for distance between blob descriptors (0.5 is recommended)
	 * 			[-1,-1] specifies an inward direction of up and to the left in the camera's field of view.
	 */
	public Tracker(double in_x, double in_y, double cutoff){
		inx=in_x;
		iny=in_y;
		match_cutoff=cutoff;
	}
	/**
	 * MODIFIES: this
	 * EFFECTS: adds each blob in b to appropriate track, creating new tracks if best match is less than cutoff
	 */
	public void add(BlobBag b){
		if(size()==0)
		{
			java.util.Iterator<Blob> it=b.listIterator();
			while(it.hasNext())
			{
				tracks.add(new Track(it.next()));
			}
		}
		else
		{
			java.util.Iterator<Blob> it=b.listIterator();
			while(it.hasNext())
			{
				Blob blob=it.next();
				Track maxtrack=null;
				double maxval=-100;
				ListIterator<Track> trit=tracks.listIterator();
				while(trit.hasNext())
				{
					Track t=trit.next();
					double val=blob.getDescription().distanceTo(t.mostRecent().getDescription());
					if(val>maxval)
					{
						maxval=val;
						maxtrack=t;
					}
				}
				if(maxval>match_cutoff)
				{
					maxtrack.add(blob);
				}
				else
				{
					tracks.add(new Track(blob));
				}
			}
		}
		last_add_time2=last_add_time;
		last_add_time=b.getStamp().getTime();
	}
	/**
	 * MODIFIES: this
	 * EFFECTS: discards all tracks that have not been used since time
	 */
	public void remove(java.util.Date date){
		ListIterator<Track> trit=tracks.listIterator();
		while(trit.hasNext())
		{
			Track t=trit.next();
			if(t.mostRecent().getStamp().getTime()<date.getTime())
			{
				trit.remove();
			}
		}
	}
	/**
	 * EFFECTS: returns number of tracks
	 */
	public int size(){
		return tracks.size();
	}
	/**
	 * MODIFIES: this
	 * EFFECTS:  computes the current person count
	 * 	updates (+/- counts) are accumulated for tracks that have no matches for last number of milliseconds specified
	 * 	no-op if there have been no BlobBags added during that time
	 * 	tracks that are accumulated into count are discarded
	 */
	public int computeCount(long milliseconds)
	{
		long now=java.util.Calendar.getInstance().getTimeInMillis();
		if(now-last_add_time2>=milliseconds) now=last_add_time2;
		ListIterator<Track> trit=tracks.listIterator();
		while(trit.hasNext())
		{
			Track t=trit.next();
			long then=t.mostRecent().getStamp().getTime();
			if(then<(now-milliseconds))
			{
				double[] vel=t.firstVelocity();
				double fdot=vel[0]*inx+vel[1]*iny/(vel[0]*vel[0]+vel[1]*vel[1]+inx*inx+iny*iny);
				vel=t.lastVelocity();
				double ldot=vel[0]*inx+vel[1]*iny/(vel[0]*vel[0]+vel[1]*vel[1]+inx*inx+iny*iny);
				if(ldot>0 && fdot>0) ++count;
				else if(ldot<0 && fdot<0) --count;
				trit.remove();
			}
		}
		return count;
	}
	/**
	 * 
	 * EFFECTS: returns last computed count
	 */
	public int getCount()
	{
		return count;
	}
	private Vector<Track> tracks=new Vector<Track>();
}
